﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;

namespace SharpGen.Addin
{
    [RunInstaller(true)]
    public partial class AddinInstaller : Installer
    {
        private const string ExtNameSpace = "http://schemas.microsoft.com/AutomationExtensibility";

        #region public AddinInstaller()
        /// <summary>
        /// Initializes a new instance of the <b>AddinInstaller</b> class.
        /// </summary>
        public AddinInstaller()
        {
            InitializeComponent();
        }
        #endregion

        #region public override void Install(IDictionary stateSaver)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="stateSaver"></param>
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);

            string assemblyName = this.Context.Parameters["AssemblyName"];
            string assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            try
            {
                UpdateAddinControlFile(assemblyName, assemblyPath, stateSaver);
                UpdateAddinConfigFile(assemblyName, assemblyPath);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        #endregion

        #region private void UpdateAddinControlFile(string assemblyName, string assemblyPath, IDictionary stateSaver)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="assemblyPath"></param>
        /// <param name="stateSaver"></param>
        private void UpdateAddinControlFile(string assemblyName, string assemblyPath, IDictionary stateSaver)
        {
            string addinAssemblyFileName = assemblyName + ".dll";
            string addinControlFileName = assemblyName + ".Addin";
            string addinTargetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"Visual Studio 2008\Addins");

            DirectoryInfo dirInfo = new DirectoryInfo(addinTargetPath);
            if (!dirInfo.Exists)
            {
                dirInfo.Create();
            }

            string sourceFile = Path.Combine(assemblyPath, addinControlFileName);
            if (!File.Exists(sourceFile))
            {
                return;
            }
            XmlDocument doc = new XmlDocument();
            doc.Load(sourceFile);
            XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
            xnm.AddNamespace("def", ExtNameSpace);

            // Update Addin/Assembly node

            XmlNode node = doc.SelectSingleNode("/def:" +
                "Extensibility/def:Addin/def:Assembly", xnm);
            if (node != null)
            {
                node.InnerText = Path.Combine(assemblyPath, addinAssemblyFileName);
            }

            // Update ToolsOptionsPage/Assembly node

            node = doc.SelectSingleNode("/def:Extensibility/def:" +
                   "ToolsOptionsPage/def:Category/def:SubCategory/def:Assembly", xnm);
            if (node != null)
            {
                node.InnerText = Path.Combine(assemblyPath, addinAssemblyFileName);
            }

            doc.Save(sourceFile);

            string targetFile = Path.Combine(addinTargetPath, addinControlFileName);
            File.Copy(sourceFile, targetFile, true);

            // Save AddinPath to be used in Uninstall or Rollback

            stateSaver.Add("AddinPath", targetFile);
        }
        #endregion

        #region private void UpdateAddinConfigFile(string assemblyName, string assemblyPath)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="assemblyPath"></param>
        private void UpdateAddinConfigFile(string assemblyName, string assemblyPath)
        {
            string addinAssemblyFileName = assemblyName + ".dll";
            string addinConfigFileName = assemblyName + ".dll.config";

            string sourceFile = Path.Combine(assemblyPath, addinConfigFileName);
            if (!File.Exists(sourceFile))
            {
                return;
            }

            XmlDocument doc = new XmlDocument();
            doc.Load(sourceFile);
            XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);

            XmlNodeList nodes = doc.SelectNodes("/configuration/userSettings/CodeGen.Addin.Properties.Settings/*");
            foreach (XmlNode nd in nodes)
            {
                if (nd.Attributes["name"].Value == "CodeGenPath")
                {
                    nd.InnerXml = string.Format("<value>{0}</value>", Path.Combine(assemblyPath, "CodeGen.exe"));
                    break;
                }
            }

            doc.Save(sourceFile);
        }
        #endregion

        #region public override void Rollback(IDictionary savedState)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="savedState"></param>
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);

            try
            {
                string fileName = (string)savedState["AddinPath"];
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        #endregion

        #region public override void Uninstall(IDictionary savedState)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="savedState"></param>
        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);

            try
            {
                string fileName = (string)savedState["AddinPath"];
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        #endregion
    }
}
